import os
import re
from datetime import datetime
from typing import Dict, List, Optional, Tuple
import pytesseract
from pdfminer.high_level import extract_text
from pdf2image import convert_from_path
import spacy
from dateutil.parser import parse
from pathlib import Path
import json
from concurrent.futures import ThreadPoolExecutor
import numpy as np
from PIL import Image

# 加载NLP模型
nlp = spacy.load("en_core_web_sm")

class ResumeParser:
    """多模态简历解析器"""
    def __init__(self, kg_client=None):
        self.kg_client = kg_client
        self.executor = ThreadPoolExecutor(max_workers=4)
        
    def parse_resume(self, file_path: str) -> Dict[str, Any]:
        """解析简历文件"""
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileNotFoundError(f"文件不存在: {file_path}")
            
        # 根据文件类型选择解析方法
        if file_path.suffix.lower() == '.pdf':
            return self._parse_pdf(file_path)
        elif file_path.suffix.lower() in ('.jpg', '.jpeg', '.png'):
            return self._parse_image(file_path)
        else:
            raise ValueError("不支持的格式，仅支持PDF和图片")
    
    def _parse_pdf(self, file_path: Path) -> Dict[str, Any]:
        """解析PDF简历"""
        # 尝试直接提取文本
        text = extract_text(str(file_path))
        
        # 如果文本提取失败或内容过少，尝试OCR
        if len(text.strip()) < 100:
            images = convert_from_path(str(file_path))
            text = "\n".join([self._ocr_image(image) for image in images])
        
        return self._parse_text(text)
    
    def _parse_image(self, file_path: Path) -> Dict[str, Any]:
        """解析图片简历"""
        image = Image.open(file_path)
        text = self._ocr_image(image)
        return self._parse_text(text)
    
    def _ocr_image(self, image: Image.Image) -> str:
        """使用OCR识别图片中的文本"""
        # 预处理图像
        image = image.convert('L')  # 灰度
        image = image.point(lambda x: 0 if x < 128 else 255, '1')  # 二值化
        
        # 使用Tesseract OCR
        custom_config = r'--oem 3 --psm 6'
        return pytesseract.image_to_string(image, config=custom_config)
    
    def _parse_text(self, text: str) -> Dict[str, Any]:
        """解析简历文本"""
        # 基本信息
        name, email, phone = self._extract_contact_info(text)
        
        # 技能
        skills = self._extract_skills(text)
        
        # 工作经历
        experiences = self._extract_experiences(text)
        
        # 教育背景
        education = self._extract_education(text)
        
        # 标准化技能
        if self.kg_client:
            standardized_skills = self._standardize_skills(skills)
        else:
            standardized_skills = skills
        
        return {
            "name": name,
            "email": email,
            "phone": phone,
            "skills": standardized_skills,
            "experiences": experiences,
            "education": education,
            "raw_text": text
        }
    
    def _extract_contact_info(self, text: str) -> Tuple[str, str, str]:
        """提取联系信息"""
        # 提取姓名
        doc = nlp(text)
        name = ""
        for ent in doc.ents:
            if ent.label_ == "PERSON":
                name = ent.text
                break
        
        # 提取邮箱
        email_regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
        email_match = re.search(email_regex, text)
        email = email_match.group(0) if email_match else ""
        
        # 提取电话
        phone_regex = r'(\+?\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b'
        phone_match = re.search(phone_regex, text)
        phone = phone_match.group(0) if phone_match else ""
        
        return name, email, phone
    
    def _extract_skills(self, text: str) -> List[str]:
        """提取技能"""
        # 常见技能关键词
        skill_keywords = {
            "programming": ["Python", "Java", "C++", "JavaScript", "SQL"],
            "data": ["Machine Learning", "Data Analysis", "Statistics"],
            "tools": ["Git", "Docker", "AWS"]
        }
        
        # 从文本中匹配技能
        found_skills = []
        for category, skills in skill_keywords.items():
            for skill in skills:
                if skill.lower() in text.lower():
                    found_skills.append(skill)
        
        # 使用NLP提取名词短语作为潜在技能
        doc = nlp(text)
        noun_phrases = [chunk.text for chunk in doc.noun_chunks]
        found_skills.extend(noun_phrases)
        
        return list(set(found_skills))
    
    def _standardize_skills(self, skills: List[str]) -> List[str]:
        """标准化技能名称"""
        if not self.kg_client:
            return skills
            
        standardized = []
        for skill in skills:
            # 查询知识图谱中最接近的技能
            similar = self.kg_client.find_similar_skills(skill, top_k=1)
            if similar:
                standardized.append(similar[0]["name"])
            else:
                standardized.append(skill)
        return standardized
    
    def _extract_experiences(self, text: str) -> List[Dict[str, Any]]:
        """提取工作经历"""
        # 分割文本为段落
        paragraphs = [p.strip() for p in text.split('\n') if p.strip()]
        
        experiences = []
        current_exp = {}
        
        # 简单正则匹配工作经历
        date_regex = r'(\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\s+\d{4}\b|\d{4})\s*[-–—]\s*(\b(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\s+\d{4}\b|\d{4}|Present|present|Now|now)'
        
        for i, para in enumerate(paragraphs):
            # 检查是否包含日期范围
            date_match = re.search(date_regex, para)
            if date_match:
                if current_exp:  # 保存前一段经历
                    experiences.append(current_exp)
                    current_exp = {}
                
                start_date = self._parse_date(date_match.group(1))
                end_date = self._parse_date(date_match.group(2))
                
                current_exp = {
                    "position": paragraphs[i-1] if i > 0 else "",
                    "company": "",
                    "start_date": start_date,
                    "end_date": end_date,
                    "description": []
                }
            elif current_exp and len(para.split()) > 3:  # 假设长段落是描述
                current_exp["description"].append(para)
        
        if current_exp:
            experiences.append(current_exp)
        
        return experiences
    
    def _parse_date(self, date_str: str) -> Optional[str]:
        """解析日期字符串"""
        if not date_str or date_str.lower() in ("present", "now"):
            return None
            
        try:
            dt = parse(date_str)
            return dt.strftime("%Y-%m-%d")
        except:
            return None
    
    def _extract_education(self, text: str) -> List[Dict[str, Any]]:
        """提取教育背景"""
        education_keywords = ["University", "College", "Bachelor", "Master", "PhD"]
        paragraphs = [p.strip() for p in text.split('\n') if p.strip()]
        
        education = []
        for para in paragraphs:
            if any(keyword.lower() in para.lower() for keyword in education_keywords):
                # 尝试提取年份
                year_match = re.search(r'\b(19|20)\d{2}\b', para)
                degree = self._identify_degree(para)
                
                edu_item = {
                    "institution": para,
                    "degree": degree,
                    "year": year_match.group(0) if year_match else None
                }
                education.append(edu_item)
        
        return education
    
    def _identify_degree(self, text: str) -> str:
        """识别学位类型"""
        text = text.lower()
        if "phd" in text or "doctor" in text:
            return "PhD"
        elif "master" in text:
            return "Master"
        elif "bachelor" in text:
            return "Bachelor"
        return "Other"

if __name__ == "__main__":
    # 示例使用
    parser = ResumeParser()
    
    # 解析示例简历
    sample_resume = """
    John Doe
    johndoe@example.com | (123) 456-7890
    
    EXPERIENCE
    Senior Software Engineer
    TechCorp • Jan 2018 – Present
    - Developed machine learning models using Python
    - Led team of 5 engineers
    - Implemented CI/CD pipeline with Docker
    
    Education
    Master of Computer Science
    State University • 2016
    """
    
    result = parser._parse_text(sample_resume)
    print(json.dumps(result, indent=2))